﻿package com.calefk.core  {

    import com.calefk.core.LoadFiles;
    import com.calefk.util.Generic;
    import flash.display.MovieClip;
    import flash.events.Event;
    import flash.events.IOErrorEvent;
    import flash.events.KeyboardEvent;
    import flash.utils.getTimer;
    
    
    /**
     * Clase inicial y principal de la aplicación, 
     * 
     */
	public class Project {
        
        // instancia del proyecto
        public static var instance:Project;

        // public var lb_assets:Library;
        public var lb_sounds:Library;
        
        public var lb_list_assets:Array = new Array();
        
        // asignamos un % para la carga de recursos 
        // por defecto lso archivos XML representaran el 5%
        // y los graficos + sonidos representan el 90% ,
        // el 5% representa el codigo
        protected var PERCENT_INIT_XML       :Number = 1;
        protected var PERCENT_INIT_RESOURCES :Number = 1;
        
        protected var PERCENT_XML        :Number = 5;
        protected var PERCENT_RESOURCES  :Number = 90;
        
        private static const ST_LOAD_INCRUSTED   :int = 0;
        private static const ST_LOAD_INIT        :int = 1;
        private static const ST_LOAD_OTHER       :int = 2;
        private static const ST_NONE             :int = 3;
		private static const ST_UPDATE           :int = 4;
        private var mStateProject:int = ST_LOAD_INCRUSTED;
        
        private var mPercentIncrusted:Number = 100;
        private var mCurrentPercent:Number = 0;
        
		public static var PW:Number = 600;
		public static var PH:Number = 400;
		
		private var mOldTime:int;
		protected var mCanvas:MovieClip;

        protected var mBasePath:String = "";
        
		protected var mPageManager:PageManager;
		
		protected var mListTask:List;
        
        protected var mLoadOthers:LoadFiles;
		protected var mLoadInit  :LoadFiles;
				
		public function get pageManager():PageManager { return mPageManager; }
		public function get canvas():MovieClip { return mCanvas; }
        public function get basePath():String { return mBasePath; }
		
		public function Project(canvas:MovieClip , path:String = null):void {
			mCanvas = canvas;
			// mCanvas.addEventListener(Event.ENTER_FRAME , onEnterFrame , false  , 0 , true);
			// mCanvas.addEventListener(IOErrorEvent.IO_ERROR , onIOErrorProject , false , 0 , true);
            
            // asignar porcentajes para los demas
            assignPercents();
			
            mBasePath = path;
            // read base path
			if (mBasePath == null) {
				var flashVars:* = mCanvas.loaderInfo.parameters;
				
				if (flashVars.basePath != undefined) {
					mBasePath = flashVars.basePath;
				} else {
					mBasePath = "";
				}
			}
            trace("::: BasePath : " + mBasePath);
			
            // para cargar archivos y ponder manejarlo en memoria
            mLoadInit  = new LoadFiles(PERCENT_INIT_RESOURCES, PERCENT_INIT_XML);
            mLoadInit.onProgressPercent = onProgressPercent;
            mLoadInit.onEndLoad = onEndLoadInitFiles;
            // invocar metodo de carga inicial
            onFilesInit();
            
            // para cargar el resto de recursos
            mLoadOthers = new LoadFiles(PERCENT_RESOURCES, PERCENT_XML);
            mLoadOthers.onProgressPercent = onProgressPercent;
            mLoadOthers.onEndLoad = onEndLoadOtherFiles;
            
            mPercentIncrusted -= (PERCENT_INIT_RESOURCES + PERCENT_INIT_XML);
            mPercentIncrusted -= PERCENT_XML;
            mPercentIncrusted -= PERCENT_RESOURCES;

			mListTask = new List();
		}
        /**
         * Sirve para asignar los porcentajes de los recursos del proyecto,
         * se puede modificar : PERCENT_INIT_XML , PERCENT_INIT_RESOURCES
         * PERCENT_XML , PERCENT_RESOURCES
         */
        protected function assignPercents():void {
        }
        
        private function onEndLoadOtherFiles():void {
            // remove events
            // mCanvas.removeEventListener(Event.ENTER_FRAME , onEnterFrame);
            // mCanvas.removeEventListener(IOErrorEvent.IO_ERROR , onIOErrorProject);                            
			mStateProject = ST_NONE;
            mCurrentPercent += mLoadOthers.currentPercent;
            onEndLoad();
        }
        
        private function onEndLoadInitFiles():void {
            // cargar otros archivos
            onPrepareFiles();
            
            if (mLoadOthers.numFiles() > 0) {
                // increment percent
                mCurrentPercent += mLoadOthers.currentPercent;                

                // cargar los otros recursos
                mLoadOthers.init(mCurrentPercent);
                mStateProject = ST_LOAD_OTHER;
            } else {
               // mCanvas.removeEventListener(Event.ENTER_FRAME , onEnterFrame);
               // mCanvas.removeEventListener(IOErrorEvent.IO_ERROR , onIOErrorProject);                            
				mStateProject = ST_NONE;
                onEndLoad();
            }
        }
		/**
		 *  Agrega una tarea para ejecutar
		 * @param	exec funcion a ejecutar
		 * @param	delay tiempo de espera para ejecutar
		 */
		public function addTask(exec:Function , delay:int):void {
			mListTask.add(new Task(exec , delay));
		}
		/**
		 * Permite cargar archivos XML antes de que comienze a cargar los SWF,
         * el objetivo es tener en memoria el XMl para usarlo antes de cargar otros archivos
		 */
        protected function onFilesInit():void {
            
        }
        
        /**
         * Sobreescribir este metodo para añadir archivos de carga
         */
        protected function onPrepareFiles():void { }
        
        /**
         * 
         * @param	_filePath ruta del archivo a cargar
         * @param	_nameClass clase que tiene la estructura del XML
         * @param	_objReference objeto o clase que alberga una variable
         * @param	_propertyName es la variable que contendra la estructura XML
         */
        protected function addFileXML(_filePath:String , _objReference:* ):void {
            mLoadOthers.addFileXML(mBasePath + _filePath , FileManager.FILE_XML ,_objReference);
        }
        
        protected function addFileSWF(_filePath:String , _objReference:*):void {
            mLoadOthers.addFileSWF(mBasePath + _filePath , FileManager.FILE_SWF , _objReference);
        }        
		
        
        protected function addFileXMLInit(_filePath:String , _objReference:* ):void {
            mLoadInit.addFileXML(mBasePath + _filePath , FileManager.FILE_XML ,_objReference);
        }
        
        protected function addFileSWFInit(_filePath:String , _objReference:*):void {
            mLoadInit.addFileSWF(mBasePath + _filePath , FileManager.FILE_SWF , _objReference);
        }     
		
		public function update():void {
			onEnterFrame(null);
		}
        
		private function onEnterFrame(e:Event):void {
            
            switch (mStateProject) {
                case ST_LOAD_INCRUSTED:
                
                    if (mCanvas.loaderInfo.bytesLoaded == mCanvas.loaderInfo.bytesTotal) {
                         
                        mCurrentPercent += mPercentIncrusted;
                        
                        if (mLoadInit.numFiles() > 0) {
                            mLoadInit.init(mCurrentPercent);
                            mStateProject = ST_LOAD_INIT;
                        } else {
                            // preparar la carga de otros archivos
                            onPrepareFiles();
                            
                            if (mLoadOthers.numFiles() > 0) {
                                mLoadOthers.init(mCurrentPercent);
                                mStateProject = ST_LOAD_OTHER;
                            } else {
                                // remove enter frame
                                // mCanvas.removeEventListener(Event.ENTER_FRAME , onEnterFrame);
                                // mCanvas.removeEventListener(IOErrorEvent.IO_ERROR , onIOErrorProject);                            
								mStateProject = ST_NONE;
                                // call event
                                onEndLoad();                            
                            }
                        }

                    } else {
                        // ------- loading percent ----------
                        var percent:Number = mCanvas.loaderInfo.bytesLoaded * mPercentIncrusted / mCanvas.loaderInfo.bytesTotal;
                        onProgressPercent(percent , 100);
                    }
                
                    break;
                case ST_LOAD_INIT:
                    if (mLoadInit) {
                        mLoadInit.update();
                    }
                    break;
                case ST_LOAD_OTHER:
                    if (mLoadOthers) {
                        mLoadOthers.update();
                    }
                    break;
				case ST_NONE:
					break;
				case ST_UPDATE:
					// actualizar el contendio del proyecto
					updateProject(null);
					break;
            }
		}
        /**
         * override this method for loading
         * @param	percent
         * @param	total
         */
        protected function onProgressPercent(percent:Number , total:Number ):void {
            
        }
        /**
         * Sobreescribir este metodo cuando se requiera hacer justo cuando se termine de cargar
         * la aplicacion.
         */
        protected function onEndLoad():void {
            onRedirectToInit();
        }
        
        private function onIOErrorProject(e:IOErrorEvent):void {
            trace("::: Error Flash IOError : " + e.toString());
        }
            
		
		protected function onRedirectToInit():void {
			mCanvas.gotoAndStop("PROJECT");
		}
		
		// call from fla
		
		public function onBuild():void {
			mStateProject = ST_UPDATE;
			// create update event
			// mCanvas.addEventListener(Event.ENTER_FRAME , update , false , 0 , true);
			//mOldTime = getTimer();
            mOldTime = new Date().getTime();

			// add event keyboard events
			mCanvas.stage.addEventListener(KeyboardEvent.KEY_DOWN , onKeyDown , false , 0 , true);
			mCanvas.stage.addEventListener(KeyboardEvent.KEY_UP , onKeyUp , false , 0 , true);
			// pagina de inicio
			mPageManager = getNewPageManager();
			onInit();
		}
		
		protected function onInit():void { }
		// ----------------
		// override methods
		// ----------------
		protected function getNewPageManager():PageManager {
			return new PageManager(mCanvas.mcCanvasProject);
		}
		
		private function updateProject(e:Event):void {
            var now:Number = (new Date()).getTime();
            var dt:Number = now - mOldTime;
            mOldTime = now;

            // fix para los delta de tiempos
            // -------------
            if (dt <= 0) {
                dt = 33;
            }
            // -------------
            
			if (mListTask) {
				mListTask.update(dt);
			}
			
			if (mPageManager) {
				mPageManager.update(dt);
			}
		}
		// ---------------
		// events keyboard
		// ---------------
		private function onKeyDown(e:KeyboardEvent):void {
			if (mPageManager) {
				mPageManager.onKeyDown(e);
			}
		}
		
		private function onKeyUp(e:KeyboardEvent):void {
			if (mPageManager) {
				mPageManager.onKeyUp(e);
			}
		}
        
        /*public function setDefaultAssets(_filePath:String):void {
            lb_assets = new Library();
            mLoadOthers.addFileSWF(mBasePath + _filePath , FileManager.FILE_SWF , lb_assets);
        }*/
        
        public function setDefaultSounds(_filePath:String):void {
            lb_sounds = new Library();
            mLoadOthers.addFileSWF(mBasePath + _filePath , FileManager.FILE_SWF , lb_sounds);
        }
        
        public function addAssets(_filePath:String):void {
            var lb_assets:Library = new Library();
            lb_list_assets.push(lb_assets);
            mLoadOthers.addFileSWF(mBasePath + _filePath , FileManager.FILE_SWF , lb_assets);            
        }
        
        public function getMovie(id:String):MovieClip {
            // busca el movieclip si existe en las librerias
            // sino existe busca en el main.swf , si aun con eso no existe retornará nulo
            var size:int = lb_list_assets.length;
            var mc:MovieClip = null;
            for (var k:int = 0; k < size; k++) {
                var lib:Library = Library(lb_list_assets[k]);
                mc = lib.getMovieClip(id);
                if (mc != null) {
                    break;
                }
            }
            if (mc == null) {
				trace( "mc no exist library: " + mc );
                return Generic.getMovie(id);
            } else {
                return mc;
            }
        }
		
		public function getClassAsset(id:String):Class {
            // busca el movieclip si existe en las librerias
            // sino existe busca en el main.swf , si aun con eso no existe retornará nulo
            var size:int = lb_list_assets.length;
            var mc:Class = null;
            for (var k:int = 0; k < size; k++) {
                var lib:Library = Library(lb_list_assets[k]);
                mc = lib.getClass(id);
                if (mc != null) {
                    break;
                }
            }
            return mc;
		}
		
		public function clean():void {
			// remove events
			mCanvas.stage.removeEventListener(KeyboardEvent.KEY_DOWN , onKeyDown);
			mCanvas.stage.removeEventListener(KeyboardEvent.KEY_DOWN , onKeyUp);

			if (mLoadInit) {
				mLoadInit.clean();
				mLoadInit = null;
			}
			
			if (mLoadOthers) {
				mLoadOthers.clean();
				mLoadOthers = null;
			}
			
			if (mPageManager) {
				mPageManager.clean();
			}
			
			// empty sounds library
			lb_sounds.clean();
			lb_sounds = null;
			
			
			// empty lib asset
			if (lb_list_assets.length > 0) {
				for (var k:int = 0 ; k < lb_list_assets.length; k++) {
					lb_list_assets[k].clean();
					lb_list_assets[k] = null;
				}
				lb_list_assets.splice(0 , lb_list_assets.length);
			}
			lb_list_assets = null;
		}
	}
}